


////////////////////////////////////////////////////////////////////////////////
module up_link_ctrl(		//input
					clk,
					nrst,
					down_link_req,	//from down_link				
					//a_o_addr,		//from down_link
					rdc,			//from uart
					tdc,			//from uart
					data_rx,		//from uart
					ack,			//from sram_ctr
					
					//output
					en_tx,			//to uart
					up_link_req,	//to down_link
					error_ul,
					s_o_addr,		//to down_link
					addr,			//address to sram_ctr
					rd,				//to sram_ctr
					wr,			//to sram_ctr
					led
					//nstate_ul,state_tx
					);
//input					
input				clk,
					nrst,
					rdc,
					tdc,
					down_link_req,
					ack;

input	[7:0]		data_rx;

//output
output				up_link_req,
					en_tx,
					error_ul,
					wr,
					rd;		
output	[12:0]		addr,
					s_o_addr;
output  [3:0]       led;

reg 	[4:0] state;
reg 	[4:0] nstate;
reg 	en_tx_r,
		up_link_req_r,
		sram_wr,
		sram_rd;
reg [12:0] sram_addr;
reg flag;

parameter a_o_addr  =	13'h1d0b;//this is the addr which the end addr of the data 
								// which module down_link_ctrl write to the sram
parameter  data_start_addr = 13'h1d00 ;

parameter IDLE            = 5'd0,   INIT_H1_RX   = 5'd1,   INIT_LEN_RX     = 5'd2,    INIT_D_RX      = 5'd3,
		  WAIT_INIT_RESP  = 5'd4,   INIT_RESP_R  = 5'd5,   INIT_RESP_R_TX  = 5'd6,    INIT_RESP_TX   = 5'd7,
          WAIT_SCRIPT     = 5'd8,   SCRIPT_W     = 5'd9,   SCRIPT_RX       = 5'd10,   TEST_BEGIN_H1  = 5'd11,
		  TEST_BEGIN_LEN  = 5'd12,  TEST_BEGIN_D = 5'd13,  WAIT_RESP       = 5'd14,   RESP_R         = 5'd15,
          RESP_R_TX       = 5'd16,  RESP_TX      = 5'd17,  WAIT_NEXT_TEST  = 5'd18;

assign   en_tx     = (nrst) ?   en_tx_r	    : 1'b0;
assign up_link_req = (nrst) ? up_link_req_r : 1'b0;
assign     wr      = (nrst) ? sram_wr       : 1'b0;
assign     rd      = (nrst) ? sram_rd       : 1'b0;
assign    addr     = (nrst) ? sram_addr     : 13'd0;
assign    s_o_addr  =   13'h0000;
assign  led = (state<INIT_LEN_RX)?state : ((state<TEST_BEGIN_LEN)?(state - 4'b0010):(state <= WAIT_NEXT_TEST?(state[4:0] - 4'b0011) : 4'd0));
 

 
always@(posedge clk or negedge nrst)
if(!nrst)
	state <= IDLE;
else 
	state <= nstate;
	
	
always@(*)
if(!nrst)
	nstate = IDLE;
else case (state)
	   IDLE        :  nstate  = (rdc && (data_rx == 8'h20)) ? INIT_H1_RX  : IDLE;
	INIT_H1_RX     :  nstate  = (rdc && (data_rx == 8'h00)) ? INIT_LEN_RX : INIT_H1_RX;
	INIT_LEN_RX    :  nstate  = (rdc && (data_rx == 8'h01)) ? INIT_D_RX   : INIT_LEN_RX;
	INIT_D_RX      :  nstate  = (rdc && (data_rx == 8'h20)) ? WAIT_INIT_RESP : INIT_D_RX;
	WAIT_INIT_RESP : nstate = (down_link_req) ? INIT_RESP_R : WAIT_INIT_RESP;
	INIT_RESP_R    : nstate = INIT_RESP_R_TX ;
	INIT_RESP_R_TX : nstate = (ack) ? INIT_RESP_TX : INIT_RESP_R_TX;
	INIT_RESP_TX   : begin
					if(tdc && (sram_addr != a_o_addr))
						nstate =  INIT_RESP_R ;
					else if (rdc && (data_rx == 8'h21))
						 nstate =  TEST_BEGIN_H1 ;
						 else if (rdc && (data_rx != 8'h21))
								nstate = WAIT_SCRIPT ;
							 else 
									nstate =  INIT_RESP_TX ;
					end
	WAIT_SCRIPT    : nstate = SCRIPT_W ;
	SCRIPT_W       : nstate = (ack) ?  SCRIPT_RX : SCRIPT_W ; 
	SCRIPT_RX      : nstate = (rdc) ? ((data_rx == 8'h21) ? TEST_BEGIN_H1  : SCRIPT_W ) : SCRIPT_RX;
	TEST_BEGIN_H1  : nstate = (rdc && (data_rx == 8'h00)) ? TEST_BEGIN_LEN : TEST_BEGIN_H1;
	TEST_BEGIN_LEN : nstate = (rdc && (data_rx == 8'h01)) ? TEST_BEGIN_D   : TEST_BEGIN_LEN;
	TEST_BEGIN_D   : nstate = (rdc && (data_rx == 8'h21)) ? WAIT_RESP      : TEST_BEGIN_D;
	WAIT_RESP      : nstate = (down_link_req) ? RESP_R   : WAIT_RESP;
	RESP_R         : nstate = RESP_R_TX ;
	RESP_R_TX      : nstate =  (ack) ? RESP_TX :RESP_R_TX;
	RESP_TX        : begin
					  if(tdc && (sram_addr != a_o_addr))
							nstate =  RESP_R ;
					  else if(tdc && (sram_addr == a_o_addr))
								nstate =  WAIT_NEXT_TEST ;
							else 
								nstate = RESP_TX;
					 end
	WAIT_NEXT_TEST : nstate = (rdc && (data_rx == 8'h21)) ? TEST_BEGIN_H1 : WAIT_NEXT_TEST;
	default        : nstate =  IDLE; 
	endcase

always@(posedge clk or negedge nrst)
if(!nrst)
	begin
	    en_tx_r     <= 1'b0;
		up_link_req_r <= 1'b0;
		sram_wr     <= 1'b0;
		sram_rd     <= 1'b0;
		sram_addr   <= 13'd0;
	end				
else case(state)
		  IDLE :
			begin
				en_tx_r     <= 1'b0;
				up_link_req_r <= 1'b0;
				sram_wr     <= 1'b0;
				sram_rd     <= 1'b0;
				sram_addr   <= 13'd0;
			end
			INIT_H1_RX , INIT_H1_RX , INIT_LEN_RX: 
			begin
				en_tx_r       <= 1'b0;
				up_link_req_r <= 1'b0;
				sram_wr       <= 1'b0;
				sram_rd       <= 1'b0;

			end
			INIT_D_RX:
			begin
				if(rdc && (data_rx == 8'h20))
					up_link_req_r <= 1'b1;
			end
			
			WAIT_INIT_RESP:
			begin
				
				up_link_req_r <= 1'b0;
				if(down_link_req)
				sram_addr   <= data_start_addr;
			end
			
			INIT_RESP_R:
			begin
				  en_tx_r     <= 1'b0;
				up_link_req_r <= 1'b0;
				sram_rd       <= 1'b1;
			end
			
			INIT_RESP_R_TX :
			begin
				if(ack)
				begin
					sram_rd     <= 1'b0;
				    en_tx_r     <= 1'b1;
					sram_addr   <= sram_addr + 1'b1;
				end
			end
			INIT_RESP_TX :
			begin
				en_tx_r   <= 1'b0;	
			end
			
			WAIT_SCRIPT :
			begin
				sram_addr <= s_o_addr;
			end
			
			SCRIPT_W :
			begin
				 sram_wr <=  1'b1;
				 if(ack)
				begin
					sram_wr <= 1'b0;
					sram_addr <= sram_addr + 1'b1;
				end
			end

			
		 SCRIPT_RX , TEST_BEGIN_H1 , TEST_BEGIN_LEN:
			begin
				sram_rd <= 1'b0;
				sram_wr <= 1'b0;
			end
		   TEST_BEGIN_D:
		   begin
            if(rdc && (data_rx == 8'h21))
                up_link_req_r <= 1'b1;
		   end
		   
		   WAIT_RESP:
		   begin
			up_link_req_r <= 1'b0;
			if(down_link_req)
				begin
					sram_addr <= data_start_addr;
				end
		   end
		   
		   RESP_R:
		   begin
		    up_link_req_r <= 1'b0;
			sram_rd <=  1'b1;
		   end
		   
		   RESP_R_TX:
		   begin
			if(ack)
			 begin
				sram_addr <=  sram_addr + 1'b1;
				en_tx_r   <=  1'b1;
				sram_rd   <=  1'b0;
			end
		   end
		   
		   RESP_TX:
		   begin
			en_tx_r <= 1'b0;
		   end
		   
		   WAIT_NEXT_TEST :
		   begin
				en_tx_r     <= 1'b0;
				up_link_req_r <= 1'b0;
				sram_wr     <= 1'b0;
				sram_rd     <= 1'b0;
				//sram_addr   <= 13'd0;
		   end
		   
		  endcase
		
endmodule

	
